#ifndef BOID_H
#define BOID_H
#include "../../../../addons/ofxVectorMath/src/ofxVec3f.h"
#include "../../../../addons/ofxVectorMath/src/ofxVec2f.h"
#include "ofMain.h"
#include <deque>
#include "lq.h"


#define PROCESSING_STYLE // align with velocity instead of forward
typedef ofxVec2f Vec2;

class Boid
{
    vector<Boid*> *boids;
    lqDB* hostLqDB;
    lqClientProxy lqClient;

    Vec2 steering_force;
    Vec2 steering_direction;

    Vec2 steerToFlock (void);
    void applySteeringForce (Vec2 force, const float elapsedTime);
    Vec2 smoothedAcceleration;

    // steering behaviours
    Vec2 steerForSeek (const Vec2& target);
    Vec2 steerForFlee (const Vec2& target);
    Vec2 steerForPursuit (const Boid& quarry);
    Vec2 steerForPursuit (const Boid& quarry, const float maxPredictionTime);
    Vec2 steerForEvasion (const Boid& menace, const float maxPredictionTime);
    Vec2 steerForWander (float dt);
    Vec2 steerForCohesion (const float maxDistance, const float cosMaxAngle, const vector<Boid*>& flock);
    Vec2 steerForSeparation (const float maxDistance, const float cosMaxAngle, const vector<Boid*>& flock);
    Vec2 steerForAlignment (const float maxDistance, const float cosMaxAngle, const vector<Boid*>& flock);

    Vec2 check_boid_pos(Boid *nearby_boid, float wrap_radius);
    bool inBoidNeighborhood (const Boid& other, const float min_dist, const float max_dist, const float cosMaxAngle);
    void findNeighbors(vector<Boid*>& results);


    Vec2 position_;          // center position
    Vec2 side_;              // side    (x) basis vector
    Vec2 up_;                // up      (y) basis vector
    Vec2 forward_;           // forward (z) basis vector
    Vec2 velocity_;          // current velocity vector
    Vec2 acceleration_;      // current acceleration vector
    float mass_;                 // magnitude of point mass

    int idNr_;                   // unique id nr in flock
    float radius_;               // size of bounding sphere, for obstacle avoidance, etc.
    float speed_;                // speed along forward direction
    float maxForce_;             // the maximum steering force this vehicle can apply
    float maxSpeed_;             // the maximum speed this vehicle is allowed to move

    float separationAngle;
    float alignmentRadius;
    float alignmentAngle;
    float cohesionRadius;
    float cohesionAngle;

    deque<Vec2> trail;       // double ended list of previous positions

	public:
        // constructor and deconstructor
        Boid(vector<Boid*> *hostBoidList, lqDB* lqDatabase, int id);
        ~Boid(void);

        // accessors
        Vec2 position (void) const {return position_;}
        void     position (Vec2 p) {position_ = p;}
        Vec2 forward (void) const  {return forward_;}
        void     forward (Vec2 sf) {forward_ = sf;}
        Vec2 velocity (void) const {return forward() * speed_;}
        Vec2 acceleration (void) const {return acceleration_;}
        float mass (void) const {return mass_;}
        void  mass (float m)    {mass_ = m;}
        float radius (void) const {return radius_;}
        void  radius (float r)    {radius_ = r;}
        float speed (void) const {return speed_;}
        void  speed (float s)    {speed_ = s;}
        float maxForce (void) const {return maxForce_;}
        void  maxForce (float mf)   {maxForce_ = mf;}
        float maxSpeed (void) const {return maxSpeed_;}
        void  maxSpeed (float ms)    {maxSpeed_ = ms;}
        int id (void) const {return idNr_;}

        float separationWeight;
        float alignmentWeight;
        float cohesionWeight;
        float separationRadius;
        float neighborhoodRadius;
        float neighborhoodAngle;    // cosine to the neighborhood angle, from cos(0) to cos(180)
        ofColor boid_color;
        int trail_length;



		void flock();
		void update();
		void draw();
		void borders();

        // operator overloading
        Boid& operator=(const Boid &rhs);
        bool operator==(const Boid &other) const;
        bool operator!=(const Boid &other) const;


        // called by LQ for each clientObject in the specified neighborhood:
        // push that clientObject onto the Boid* vector in void*
        // clientQueryState
        // (parameter names commented out to prevent compiler warning from "-W")
        static void perNeighborCallBackFunction  (void* clientObject,
                                                  float /*distanceSquared*/,
                                                  void* clientQueryState)
        {
            typedef std::vector<Boid*> ctv;
            ctv& results = *((ctv*) clientQueryState);
            results.push_back ((Boid*) clientObject);
        }
};

#endif
